/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package main;

/**
 *
 * @author ZSQ
 */
/**
 * 数据生成器
 * 由基础组件与数据工程师实现
 */
import java.util.Random;

/**
 * 数据生成器
 */
public class DataGenerator {
    
    /**
     * 根据用户输入的函数生成训练数据
     */
    public static double[][] generateTrainingData(int samples, String functionExpression) {
        System.out.println("生成 " + samples + " 个训练样本，函数: " + functionExpression);

        double[][] data = new double[samples][3];
        Random rand = new Random();

        // 使用集合来避免重复数据
        java.util.Set<String> pointSet = new java.util.HashSet<>();

        for (int i = 0; i < samples; i++) {
            // 扩大数据范围到 [-5, 5]，并避免重复数据
            double x, y;
            String pointKey;
            int attempts = 0;

            do {
                x = rand.nextDouble() * 10.0 - 5.0;  // [-5, 5]
                y = rand.nextDouble() * 10.0 - 5.0;  // [-5, 5]
                pointKey = String.format("%.3f,%.3f", x, y);
                attempts++;

                // 防止无限循环
                if (attempts > 1000) break;
            } while (pointSet.contains(pointKey));

            pointSet.add(pointKey);

            double z = FunctionParser.eval(functionExpression, x, y);

            data[i][0] = x;
            data[i][1] = y;
            data[i][2] = z;
        }

        // 改进的数据标准化
        normalizeData(data);

        System.out.printf("生成 %d 个不重复的训练样本，数据范围: [-5, 5]\n", samples);
        return data;
    }
    
    private static void normalizeData(double[][] data) {
        // 找到目标值的范围
        double minZ = Double.MAX_VALUE;
        double maxZ = Double.MIN_VALUE;
        
        for (double[] sample : data) {
            minZ = Math.min(minZ, sample[2]);
            maxZ = Math.max(maxZ, sample[2]);
        }
        
        double rangeZ = maxZ - minZ;
        
        // 标准化到 [-0.8, 0.8] 范围，避免tanh饱和
        for (double[] sample : data) {
            sample[2] = ((sample[2] - minZ) / rangeZ) * 1.6 - 0.8;
        }
        
        System.out.printf("目标值范围: [%.3f, %.3f]\n", minZ, maxZ);
    }
    
    public static double[][][] splitTrainTest(double[][] data, double trainRatio) {
        int totalSamples = data.length;
        int trainSize = (int) (totalSamples * trainRatio);
        int testSize = totalSamples - trainSize;
        
        double[][] trainData = new double[trainSize][3];
        double[][] testData = new double[testSize][3];
        
        for (int i = 0; i < trainSize; i++) {
            trainData[i] = data[i];
        }
        for (int i = 0; i < testSize; i++) {
            testData[i] = data[trainSize + i];
        }
        
        return new double[][][]{trainData, testData};
    }
}